home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ASTEROID.ZIP / ASTEROID.C next >
C/C++ Source or Header  |  1994-07-10  |  7KB  |  273 lines

  1. /*
  2.  *  ASTEROID.C
  3.  *
  4.  *  David Stafford
  5.  *  Computer Shopper Magazine
  6.  *  "What's the Code?"
  7.  *  October 1994
  8.  *
  9.  *  To build: BCC ASTEROID.C GRAPHICS.LIB
  10.  */
  11.  
  12.  
  13. #include <stdio.h>
  14. #include <math.h>
  15. #include <graphics.h>
  16. #include <conio.h>
  17. #include <dos.h>
  18.  
  19.  
  20. typedef struct
  21.   {
  22.   float x, y;    // 2D coordinates, a float so we can store fractional values
  23.   } POINT;
  24.  
  25.  
  26. typedef struct
  27.   {
  28.   int    NumPoints;
  29.   POINT  Point[ 3 ];   // Three is enough for now but will have to make
  30.   } SHAPE;             // this more flexible later.
  31.  
  32.  
  33. typedef struct
  34.   {
  35.   POINT  Loc;             // Location on the screen
  36.   int    ViewAngle;       // Angle at which the object is facing
  37.   POINT  Direction;       // Direction which the object is moving, in pixels
  38.   SHAPE  Shape;           // The shape of the object
  39.   SHAPE  Screen;          // Actual points it occupies on the screen
  40.   } OBJECT;
  41.  
  42.  
  43. struct
  44.   {
  45.   OBJECT Ship;            // The players spaceship
  46.   } g;
  47.  
  48.  
  49. // Translates a point by rotating it (using simple trig).
  50.  
  51. void TranslatePoint( POINT *Dest, POINT *Src, int Angle )
  52.   {
  53.   double Radians;
  54.  
  55.   Radians = Angle * 0.01745;
  56.  
  57.   Dest->x = Src->x * cos( Radians ) - Src->y * sin( Radians );
  58.   Dest->y = Src->x * sin( Radians ) + Src->y * cos( Radians );
  59.   }
  60.  
  61.  
  62. // Translates an object's relative coordinates to actual
  63. // screen coordinates.
  64.  
  65. void TranslateObject( OBJECT *Object )
  66.   {
  67.   int i;
  68.  
  69.   for( i = 0; i < Object->Shape.NumPoints; i++ )
  70.     {
  71.     // First, account for rotation
  72.     TranslatePoint( &Object->Screen.Point[ i ], &Object->Shape.Point[ i ], Object->ViewAngle );
  73.  
  74.     // Now make it relative to the screen location
  75.     Object->Screen.Point[ i ].x += Object->Loc.x;
  76.     Object->Screen.Point[ i ].y += Object->Loc.y;
  77.     }
  78.   }
  79.  
  80.  
  81. // Goes through the list of points in an object
  82. // and connects them all with lines.
  83.  
  84. void DrawObject( OBJECT *Object )
  85.   {
  86.   int i;
  87.  
  88.   for( i = 1; i < Object->Shape.NumPoints; i++ )
  89.     {
  90.     line( Object->Screen.Point[ i - 1 ].x, Object->Screen.Point[ i - 1 ].y,
  91.           Object->Screen.Point[ i     ].x, Object->Screen.Point[ i     ].y );
  92.     }
  93.  
  94.   line( Object->Screen.Point[ i - 1 ].x, Object->Screen.Point[ i - 1 ].y,
  95.         Object->Screen.Point[ 0     ].x, Object->Screen.Point[ 0     ].y );
  96.   }
  97.  
  98.  
  99. // Moves an object along its direction.
  100.  
  101. void MoveObject( OBJECT *Object )
  102.   {
  103.   Object->Loc.x += Object->Direction.x;
  104.   Object->Loc.y += Object->Direction.y;
  105.  
  106.   // Handle screen wrap-around
  107.  
  108.   if( Object->Loc.x < 0 )    Object->Loc.x = Object->Loc.x + 640;
  109.   if( Object->Loc.x > 639 )  Object->Loc.x = Object->Loc.x - 640;
  110.   if( Object->Loc.y < 0 )    Object->Loc.y = Object->Loc.y + 480;
  111.   if( Object->Loc.y > 479 )  Object->Loc.y = Object->Loc.y - 480;
  112.   }
  113.  
  114.  
  115. // This routine just waits until the display is
  116. // in a vertical retrace cycle.  This is useful
  117. // for two things: to perform drawing during retrace
  118. // when it can't be seen and (more importantly)
  119. // to provide a method of synchronizing the animation
  120. // with the game play so that it runs at a constant
  121. // speed on virtually every machine.
  122.  
  123. void SyncToVerticalRetrace( void )
  124.   {
  125.   // If we happen to be in the middle of a vertical retrace
  126.   // period wait until its over.
  127.  
  128.   while( inp( 0x3da ) & 8 )
  129.     ;
  130.  
  131.   // Wait until we begin vertical retrace.
  132.  
  133.   while( !(inp( 0x3da ) & 8) )
  134.     ;
  135.   }
  136.  
  137.  
  138. #define ROTATE_STEP  3       // Number of degrees to rotate
  139. #define SPEED        0.12    // Speed control
  140. #define FRICTION     0.995   // Speed reduction per frame
  141.  
  142. void Supervisor( void )
  143.   {
  144.   unsigned short KeyboardStatus;
  145.   int c = 0, EraseFlag = 1, Color = WHITE;
  146.  
  147.   while( c != 'q' && c != 'Q' )
  148.     {
  149.     TranslateObject( &g.Ship );
  150.  
  151.     DrawObject( &g.Ship );   // Draw the ship
  152.  
  153.     // Get the keyboard status bits from the BIOS data area
  154.  
  155.     KeyboardStatus = *(unsigned short far *)MK_FP( 0x40, 0x17 );
  156.  
  157.     MoveObject( &g.Ship );
  158.  
  159.     // Simulate friction.
  160.  
  161.     g.Ship.Direction.x *= FRICTION;
  162.     g.Ship.Direction.y *= FRICTION;
  163.  
  164.     // If a real keystroke is waiting get it
  165.  
  166.     if( kbhit() )
  167.       {
  168.       c = getch();
  169.  
  170.       if( c == 'e' || c == 'E' )
  171.         {
  172.         EraseFlag = !EraseFlag;    // Toggle erase flag
  173.         }
  174.       }
  175.  
  176.     if( KeyboardStatus & 0x0002 )    // left shift, rotate left
  177.       {
  178.       g.Ship.ViewAngle -= ROTATE_STEP;
  179.       if( g.Ship.ViewAngle < 0 )  g.Ship.ViewAngle = 360 - ROTATE_STEP;
  180.       }
  181.  
  182.     if( KeyboardStatus & 0x0001 )    // right shift, rotate right
  183.       {
  184.       g.Ship.ViewAngle += ROTATE_STEP;
  185.       if( g.Ship.ViewAngle > 359 )  g.Ship.ViewAngle = 0 + ROTATE_STEP;
  186.       }
  187.  
  188.     if( KeyboardStatus & 0x4000 )    // shift-lock, fire
  189.       {
  190.       // Not supported yet.
  191.       }
  192.  
  193.     if( KeyboardStatus & 0x0008 )    // alt, thrust
  194.       {
  195.       double Radians;
  196.  
  197.       Radians = g.Ship.ViewAngle * 0.01745;
  198.  
  199.       g.Ship.Direction.x += sin( Radians ) * SPEED;
  200.       g.Ship.Direction.y -= cos( Radians ) * SPEED;
  201.       }
  202.  
  203.     SyncToVerticalRetrace();     // Pause until vertical retrace
  204.  
  205.     if( EraseFlag )  DrawObject( &g.Ship );    // Erase the ship
  206.  
  207.     if( c == 'c' || c == 'C' )   // Change color
  208.       {
  209.       Color ^= (WHITE ^ LIGHTGREEN);
  210.       setcolor( Color );
  211.       c = 0;
  212.       }
  213.     }
  214.   }
  215.  
  216.  
  217. // Initialization code.
  218.  
  219. void Init( void )
  220.   {
  221.   int GraphicsDriver = VGA;     // assume VGA graphics card
  222.   int GraphicsMode = VGAHI;     // use VGA 640x480 16 color mode
  223.  
  224.   initgraph( &GraphicsDriver, &GraphicsMode, NULL );
  225.   setwritemode( XOR_PUT );
  226.  
  227.   g.Ship.Shape.NumPoints = 3;
  228.  
  229.   g.Ship.Shape.Point[ 0 ].x =   0;
  230.   g.Ship.Shape.Point[ 0 ].y = -16;
  231.   g.Ship.Shape.Point[ 1 ].x =  -8;
  232.   g.Ship.Shape.Point[ 1 ].y =  +8;
  233.   g.Ship.Shape.Point[ 2 ].x =  +8;
  234.   g.Ship.Shape.Point[ 2 ].y =  +8;
  235.  
  236.   g.Ship.ViewAngle = 0;
  237.  
  238.   g.Ship.Loc.x = 320;
  239.   g.Ship.Loc.y = 240;
  240.  
  241.   g.Ship.Direction.x = 0;
  242.   g.Ship.Direction.y = 0;
  243.   }
  244.  
  245.  
  246. void Cleanup( void )
  247.   {
  248.   closegraph();
  249.   }
  250.  
  251.  
  252. void main( int Argc, char *Argv[] )
  253.   {
  254.   puts( "\n\n" );
  255.   puts( "Asteroids.  October 1994, \"What's the Code?\"\n" );
  256.   puts( "Left shift:   Rotate left" );
  257.   puts( "Right shift:  Rotate right" );
  258.   puts( "Alt:          Thrust" );
  259.   puts( "E:            Toggle 'erase' mode" );
  260.   puts( "C:            Toggle color between white and green" );
  261.   puts( "Q:            Quit\n" );
  262.  
  263.   puts( "Press any key to begin..." );
  264.  
  265.   getch();
  266.  
  267.   Init();
  268.  
  269.   Supervisor();
  270.  
  271.   Cleanup();
  272.   }
  273.